package com.zzl.redis.rock;



import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.zzl.redis.JedisUtil;
import com.zzl.redis.config.RedisPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;


public class RedisLockUtil {

//    private static Jedis singleJedis;
    private static JedisPool jedisPool;

    static {
//        JedisShardInfo jedisShardInfo = new JedisShardInfo("127.0.0.1", 6379);
//        singleJedis = JedisUtil.getSingleJedis(jedisShardInfo);
        RedisPoolConfig config = new RedisPoolConfig();
        config.setAddr("127.0.0.1");
        config.setPort(6379);
        config.setAuth("");
        config.setMaxIdle(200);
        config.setMaxActive(1024);
        config.setTestOnBorrow(true);
        config.setTimeOut(10000);
        jedisPool = JedisUtil.getJedisPool(config);
    }

    private static boolean tryLock(Jedis jedis,String lockKey,String value,int seconds) {

        try {
            if (jedis.setnx(lockKey, value) == 1){
                jedis.expire(lockKey,seconds);
                return true;
            }
            if (jedis.ttl(lockKey) == -1){// 防止 上一步 expire执行出现问题，而catch块中删除出现异常，导致 lockKey 没有设置有效期
                jedis.expire(lockKey,seconds);
            }
            return false;
        }catch (Exception e){
            e.printStackTrace();

            String lockValue = jedis.get(lockKey);
            if (value.equals(lockValue)){
                jedis.del(lockKey);
            }
            return false;
        }
    }

    private static boolean unlock(Jedis jedis,String lockKey,String value) {
        String lockValue = jedis.get(lockKey);
        if (value.equals(lockValue)){
            jedis.del(lockKey);
            return true;
        }
        return false;
    }

    private static boolean islock(Jedis jedis,String lockKey) {
        return jedis.exists(lockKey);
    }


    /**
     * @param args
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        String lockKey = "t1";
//        ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
        ExecutorService executor = Executors.newFixedThreadPool(10);
        List<Future> futureList = new ArrayList(10005);

        for (int i=0;i<10000;i++){
            EntityThread entityThread = new EntityThread(lockKey,100);
            Future future = executor.submit(entityThread);
            futureList.add(future);
        }
        for (Future future : futureList){
            future.get();
        }
        System.out.println(buffer);
        System.out.println("最终结果：atomicInteger = "+atomicInteger.get() + ",num = " + num);


	}
	public static class EntityThread implements Runnable{
        private String lockKey;
        private int lockTime;
        public EntityThread(String lockKey,int lockTime){
            this.lockKey = lockKey;
            this.lockTime = lockTime;
        }

        @Override
        public void run() {
            String idStr = snowflake.nextIdStr();
            boolean isLock = false;
            Jedis jedis = jedisPool.getResource();
            String log="";
            try {
                if (isLock = tryLock(jedis,lockKey,idStr,lockTime)){
                    doJob();
                }
                log = Thread.currentThread().getName().concat(StrUtil.format(":isLock={},idStr={}",isLock,idStr));
            }finally {
                boolean unlock = unlock(jedis,lockKey,idStr);
                log=log.concat(" ,unlock : "+ unlock);
                buffer.append(log+"\r\n");
                JedisUtil.returnResource(jedisPool,jedis);
            }
        }
    }
    private static Snowflake snowflake = IdUtil.getSnowflake(3,3);// 模仿不同的机器
    private static StringBuffer buffer = new StringBuffer();
    private static int num;
    private static AtomicInteger atomicInteger = new AtomicInteger(0);
    private static void doJob(){
        atomicInteger.incrementAndGet();
        num = num+1;
        try {
            Thread.currentThread().sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
